<template>
  <div 
    class="flow-canvas" 
    ref="canvasRef" 
    @drop="handleDrop" 
    @dragover.prevent
    @mousemove="handleCanvasMouseMove"
    @mouseup="handleCanvasMouseUp"
    @wheel.prevent="handleWheel"
    @mousedown="handleCanvasMouseDown"
    @mouseleave="handleCanvasMouseLeave"
    @click="handleCanvasClick"
  >
    <!-- 网格背景 -->
    <div 
      class="grid-background"
      :style="{
        backgroundPosition: `${translateX}px ${translateY}px`,
        backgroundSize: `${20 * scale}px ${20 * scale}px`
      }"
    ></div>
    
    <!-- 可缩放和平移的容器 -->
    <div class="transform-container" :style="transformStyle">
      <!-- 连线层 -->
      <svg class="edges-layer">
        <!-- 现有连线 -->
        <g
          v-for="edge in edges"
          :key="edge.id"
          class="edge-group"
          @mouseover="onEdgeMouseOver(edge)"
          @mouseout="onEdgeMouseOut(edge, $event)"
        >
          <!-- 添加一个宽的透明线条用于扩大点击区域 -->
          <path
            :d="calculateEdgePath(edge)"
            class="edge-hitbox"
            fill="none"
          />
          <!-- 实际显示的线条 -->
          <path
            :d="calculateEdgePath(edge)"
            class="edge-path"
            fill="none"
          />
          <!-- 悬停时显示的加号按钮 -->
          <g
            v-if="hoveredEdgeId === edge.id"
            :transform="calculatePlusPosition(edge)"
            class="plus-button"
            @mousedown.stop="showNodeList(edge)"
            pointer-events="all"
          >
            <circle r="8" fill="white" stroke="#b1b1b7" />
            <path 
              d="M -4 0 H 4 M 0 -4 V 4" 
              stroke="#b1b1b7" 
              stroke-width="1.5"
              pointer-events="none"
            />
          </g>
        </g>
        
        <!-- 临时连线 -->
        <path
          v-if="tempEdge"
          :d="calculateTempEdgePath(tempEdge)"
          class="edge-path temp-edge"
          fill="none"
          stroke="#b1b1b7"
          stroke-width="2"
          stroke-dasharray="5,5"
        />
        
        <!-- 添加箭头标记定义 -->
        <defs>
          <marker
            id="arrow"
            viewBox="0 0 10 10"
            refX="7"
            refY="5"
            markerWidth="6"
            markerHeight="6"
            orient="auto-start-reverse"
          >
            <path d="M 0 0 L 10 5 L 0 10 z" fill="#b1b1b7" />
          </marker>
        </defs>
      </svg>
      
      <!-- 节点容器 -->
      <div class="nodes-container">
        <flow-node
          v-for="node in nodes"
          :key="node.id"
          :node="node"
          @nodeMove="handleNodeMove"
          @portDragStart="handlePortDragStart"
          @portDragEnd="handlePortDragEnd"
        />
      </div>
    </div>
    
    <!-- 缩放控制器 -->
    <div class="zoom-controls">
      <button @click="zoomIn">+</button>
      <span>{{ Math.round(scale * 100) }}%</span>
      <button @click="zoomOut">-</button>
    </div>

    <!-- 节点列表弹出层 -->
    <div
      v-if="showingNodeList"
      class="node-list"
      :style="nodeListStyle"
      @mouseleave="hideNodeList"
    >
      <div
        v-for="type in nodeTypes"
        :key="type.type"
        class="node-list-item"
        @click="insertNode(type.type)"
      >
        {{ type.label }}
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, computed, watch, nextTick } from 'vue';
import type { INode, IEdge } from '../types';
import FlowNode from './FlowNode.vue';
import { v4 as uuidv4 } from 'uuid';

const nodes = ref<INode[]>([]);
const edges = ref<IEdge[]>([]);
const canvasRef = ref<HTMLElement | null>(null);
const dragStartPort = ref<any>(null);

// 添加缩放和平移状态
const scale = ref(1);
const translateX = ref(0);
const translateY = ref(0);
const isDraggingCanvas = ref(false);
const lastMouseX = ref(0);
const lastMouseY = ref(0);

// 计算变换样式
const transformStyle = computed(() => ({
  transform: `translate(${translateX.value}px, ${translateY.value}px) scale(${scale.value})`,
  transformOrigin: '0 0',
}));

// 修改获取实际坐标的函数
const getTransformedPoint = (clientX: number, clientY: number) => {
  const rect = canvasRef.value?.getBoundingClientRect();
  if (!rect) return { x: 0, y: 0 };
  
  // 从客户端坐标转换为画布坐标
  return {
    x: (clientX - rect.left - translateX.value) / scale.value,
    y: (clientY - rect.top - translateY.value) / scale.value
  };
};

// 修改获取端口位置的函数
const getPortPosition = (nodeId: string, portId: string, isInput: boolean) => {
  const node = nodes.value.find(n => n.id === nodeId);
  if (!node) return { x: 0, y: 0 };
  
  // 节点基础尺寸
  const nodeWidth = 200; // 节点宽度
  const headerHeight = 32; // 标题栏高度
  const headerPadding = 8; // 标题栏内边距

  // 计算端点位置
  const x = isInput ? 
    node.position.x : // 输入端点在左边缘
    node.position.x + nodeWidth; // 输出端点在右边缘

  // 垂直居中于标题栏
  const y = node.position.y + headerPadding + (headerHeight / 2);

  return { x, y };
};

// 修改计算连线路径的函数
const calculateEdgePath = (edge: IEdge) => {
  const sourcePos = getPortPosition(edge.source, edge.sourceHandle, false);
  const targetPos = getPortPosition(edge.target, edge.targetHandle, true);
  
  // 计算贝塞尔曲线的控制点
  const dx = Math.abs(targetPos.x - sourcePos.x);
  const offset = Math.min(dx * 0.4, 80);
  
  return `
    M ${sourcePos.x},${sourcePos.y}
    C ${sourcePos.x + offset},${sourcePos.y}
    ${targetPos.x - offset},${targetPos.y}
    ${targetPos.x},${targetPos.y}
  `.trim();
};

// 添加临时连线状态
const tempEdge = ref<{
  sourceId: string;
  sourceHandle: string;
  targetX: number;
  targetY: number;
} | null>(null);

// 修改计算临时连线路径的函数
const calculateTempEdgePath = (temp: {
  sourceId: string;
  sourceHandle: string;
  targetX: number;
  targetY: number;
}) => {
  const sourcePos = getPortPosition(temp.sourceId, temp.sourceHandle, false);
  
  // 计算贝塞尔曲线的控制点
  const dx = Math.abs(temp.targetX - sourcePos.x);
  const offset = Math.min(dx * 0.4, 80);
  
  return `
    M ${sourcePos.x},${sourcePos.y}
    C ${sourcePos.x + offset},${sourcePos.y}
    ${temp.targetX - offset},${temp.targetY}
    ${temp.targetX},${temp.targetY}
  `.trim();
};

// 修改端口拖拽开始处理函数
const handlePortDragStart = (nodeId: string, portId: string, isInput: boolean) => {
  console.log('Port drag start:', { nodeId, portId, isInput }); // 添加日志
  // 只允许从输出端口开始拖拽
  if (!isInput) {
    tempEdge.value = {
      sourceId: nodeId,
      sourceHandle: portId,
      targetX: 0,
      targetY: 0
    };
    dragStartPort.value = { nodeId, portId, isInput };
  }
};

// 修改端口拖拽结束处理函数
const handlePortDragEnd = (nodeId: string, portId: string, isInput: boolean) => {
  console.log('Port drag end:', { nodeId, portId, isInput, dragStartPort: dragStartPort.value }); // 添加日志
  
  // 只有当存在拖拽起点，并且当前端口是输入端口，且起点是输出端口时才创建连线
  if (dragStartPort.value && isInput && !dragStartPort.value.isInput) {
    console.log('Creating edge...'); // 添加日志
    const newEdge: IEdge = {
      id: uuidv4(),
      source: dragStartPort.value.nodeId,
      sourceHandle: dragStartPort.value.portId,
      target: nodeId,
      targetHandle: portId,
    };
    
    // 验证连线是否有效
    const sourceNode = nodes.value.find(n => n.id === newEdge.source);
    const targetNode = nodes.value.find(n => n.id === newEdge.target);
    
    console.log('Nodes found:', { sourceNode, targetNode }); // 添加日志
    
    const isValidConnection = sourceNode && targetNode && 
      sourceNode.data.outputs?.some(o => o.id === newEdge.sourceHandle) &&
      targetNode.data.inputs?.some(i => i.id === newEdge.targetHandle);
    
    console.log('Is valid connection:', isValidConnection); // 添加日志
    
    if (isValidConnection) {
      edges.value.push(newEdge);
      console.log('Edge created:', newEdge); // 添加日志
    }
  }
  
  // 清理临时状态
  dragStartPort.value = null;
  tempEdge.value = null;
};

// 修改画布鼠标按下处理函数
const handleCanvasMouseDown = (event: MouseEvent) => {
  // 检查是否点击了节点或其他交互元素
  const target = event.target as HTMLElement;
  const isNode = target.closest('.flow-node');
  const isPort = target.closest('.port');
  const isZoomControl = target.closest('.zoom-controls');
  
  // 如果点击的是节点、端口或缩放控件，不启动画布拖拽
  if (isNode || isPort || isZoomControl) {
    return;
  }

  isDraggingCanvas.value = true;
  lastMouseX.value = event.clientX;
  lastMouseY.value = event.clientY;
  event.preventDefault();
};

// 修改画布鼠标移动处理函数
const handleCanvasMouseMove = (event: MouseEvent) => {
  // 处理临时连线
  if (tempEdge.value && canvasRef.value) {
    const rect = canvasRef.value.getBoundingClientRect();
    const x = (event.clientX - rect.left - translateX.value) / scale.value;
    const y = (event.clientY - rect.top - translateY.value) / scale.value;
    tempEdge.value.targetX = x;
    tempEdge.value.targetY = y;
  }
  
  // 处理画布拖拽
  if (isDraggingCanvas.value) {
    const dx = event.clientX - lastMouseX.value;
    const dy = event.clientY - lastMouseY.value;
    translateX.value += dx;
    translateY.value += dy;
    lastMouseX.value = event.clientX;
    lastMouseY.value = event.clientY;
  }
};

// 修改画布鼠标抬起处理函数
const handleCanvasMouseUp = (event: MouseEvent) => {
  // 如果正在拖拽画布，则结束拖拽
  if (isDraggingCanvas.value) {
    isDraggingCanvas.value = false;
    event.preventDefault();
    return;
  }
  
  // 检查鼠标是否在某个端口上释放
  const portEl = document.elementFromPoint(event.clientX, event.clientY);
  if (portEl) {
    const portParent = portEl.closest('.port');
    if (portParent) {
      const nodeEl = portParent.closest('[data-node-id]');
      if (nodeEl) {
        const nodeId = nodeEl.getAttribute('data-node-id');
        const portId = portParent.getAttribute('data-port-id');
        const isInput = portParent.classList.contains('input-port');
        
        if (nodeId && portId) {
          handlePortDragEnd(nodeId, portId, isInput);
          return;
        }
      }
    }
  }
  
  // 如果不是在端口上释放，清理状态
  dragStartPort.value = null;
  tempEdge.value = null;
};

// 添加鼠标离开处理函数
const handleCanvasMouseLeave = () => {
  isDraggingCanvas.value = false;
};

// 添加强制更新连线的函数
const forceUpdateEdges = () => {
  // 通过创建新的数组来触发 Vue 的响应式更新
  edges.value = edges.value.map(edge => ({ ...edge }));
};

// 修改处理滚轮缩放的函数
const handleWheel = (event: WheelEvent) => {
  if (event.ctrlKey || event.metaKey) {
    const delta = -event.deltaY;
    const scaleChange = delta > 0 ? 1.1 : 0.9;
    
    const rect = canvasRef.value?.getBoundingClientRect();
    if (!rect) return;
    
    const mouseX = event.clientX - rect.left;
    const mouseY = event.clientY - rect.top;
    
    const newScale = Math.min(Math.max(scale.value * scaleChange, 0.1), 3);
    
    if (newScale !== scale.value) {
      const scaleRatio = newScale / scale.value;
      translateX.value = mouseX - (mouseX - translateX.value) * scaleRatio;
      translateY.value = mouseY - (mouseY - translateY.value) * scaleRatio;
      scale.value = newScale;
      
      // 在缩放后强制更新连线
      forceUpdateEdges();
    }
  }
};

// 修改缩放按钮处理函数
const zoomIn = () => {
  const newScale = Math.min(scale.value * 1.2, 3);
  if (newScale !== scale.value) {
    scale.value = newScale;
    // 在缩放后强制更新连线
    forceUpdateEdges();
  }
};

const zoomOut = () => {
  const newScale = Math.max(scale.value / 1.2, 0.1);
  if (newScale !== scale.value) {
    scale.value = newScale;
    // 在缩放后强制更新连线
    forceUpdateEdges();
  }
};

// 监听缩放值变化
watch(scale, (newScale, oldScale) => {
  if (newScale !== oldScale) {
    // 等待 DOM 更新后再更新连线
    nextTick(() => {
      forceUpdateEdges();
    });
  }
});

// 修改节点移动处理函数
const handleNodeMove = (nodeId: string, x: number, y: number) => {
  const node = nodes.value.find(n => n.id === nodeId);
  if (node) {
    node.position.x = x;
    node.position.y = y;
    // 在节点移动后强制更新连线
    forceUpdateEdges();
  }
};

// 修改节点拖放处理函数
const handleDrop = (event: DragEvent) => {
  const nodeType = event.dataTransfer?.getData('nodeType');
  if (nodeType && canvasRef.value) {
    const point = getTransformedPoint(event.clientX, event.clientY);
    const newNode: INode = {
      id: uuidv4(),
      type: nodeType,
      position: {
        x: point.x,
        y: point.y
      },
      data: {
        label: nodeType,
        inputs: [{ id: uuidv4(), name: 'input' }],
        outputs: [{ id: uuidv4(), name: 'output' }],
      },
    };
    nodes.value.push(newNode);
  }
};

// 添加状态
const hoveredEdgeId = ref<string | null>(null);
const showingNodeList = ref(false);
const selectedEdge = ref<IEdge | null>(null);
const nodeListPosition = ref({ x: 0, y: 0 });

// 节点类型列表
const nodeTypes = [
  { type: 'input', label: '输入节点' },
  { type: 'process', label: '处理节点' },
  { type: 'output', label: '输出节点' },
];

// 计算加号位置
const calculatePlusPosition = (edge: IEdge) => {
  const sourcePos = getPortPosition(edge.source, edge.sourceHandle, false);
  const targetPos = getPortPosition(edge.target, edge.targetHandle, true);
  
  // 计算连线中点
  const midX = (sourcePos.x + targetPos.x) / 2;
  const midY = (sourcePos.y + targetPos.y) / 2;
  
  return `translate(${midX}, ${midY})`;
};

// 处理连线悬停
const onEdgeMouseOver = (edge: IEdge) => {
  hoveredEdgeId.value = edge.id;
};

const onEdgeMouseOut = (edge: IEdge, event: MouseEvent) => {
  // 检查是否移动到加号按钮上
  const relatedTarget = event.relatedTarget as Element;
  if (relatedTarget?.closest('.plus-button')) {
    return;
  }
  hoveredEdgeId.value = null;
};

// 显示节点列表
const showNodeList = (edge: IEdge) => {
  event?.stopPropagation(); // 阻止事件冒泡到画布
  selectedEdge.value = edge;
  showingNodeList.value = true;
  
  // 获取画布元素的位置
  const canvasRect = canvasRef.value?.getBoundingClientRect();
  if (!canvasRect) return;

  // 计算连线中点在画布坐标系中的位置
  const sourcePos = getPortPosition(edge.source, edge.sourceHandle, false);
  const targetPos = getPortPosition(edge.target, edge.targetHandle, true);
  const midX = (sourcePos.x + targetPos.x) / 2;
  const midY = (sourcePos.y + targetPos.y) / 2;

  // 转换为屏幕坐标
  nodeListPosition.value = {
    x: midX * scale.value + translateX.value + canvasRect.left,
    y: midY * scale.value + translateY.value + canvasRect.top + 20
  };
};

// 添加隐藏节点列表的函数
const hideNodeList = () => {
  showingNodeList.value = false;
  selectedEdge.value = null;
};

// 修改 insertNode 函数
const insertNode = (nodeType: string) => {
  if (!selectedEdge.value) return;
  
  // 获取原始连线的起点和终点
  const sourcePos = getPortPosition(selectedEdge.value.source, selectedEdge.value.sourceHandle, false);
  const targetPos = getPortPosition(selectedEdge.value.target, selectedEdge.value.targetHandle, true);
  
  // 计算新节点在画布坐标系中的位置
  const midX = (sourcePos.x + targetPos.x) / 2;
  const midY = (sourcePos.y + targetPos.y) / 2;
  
  // 创建新节点
  const newNode: INode = {
    id: uuidv4(),
    type: nodeType,
    position: {
      x: midX - 100, // 居中放置，考虑节点宽度的一半
      y: midY - 20   // 稍微向上偏移以避免遮挡连线
    },
    data: {
      label: nodeType,
      inputs: [{ id: uuidv4(), name: 'input' }],
      outputs: [{ id: uuidv4(), name: 'output' }],
    },
  };
  
  // 添加新节点
  nodes.value.push(newNode);
  
  // 创建新连线
  const newEdges: IEdge[] = [
    {
      id: uuidv4(),
      source: selectedEdge.value.source,
      sourceHandle: selectedEdge.value.sourceHandle,
      target: newNode.id,
      targetHandle: newNode.data.inputs[0].id,
    },
    {
      id: uuidv4(),
      source: newNode.id,
      sourceHandle: newNode.data.outputs[0].id,
      target: selectedEdge.value.target,
      targetHandle: selectedEdge.value.targetHandle,
    },
  ];
  
  // 删除原连线
  edges.value = edges.value.filter(e => e.id !== selectedEdge.value?.id);
  // 添加新连线
  edges.value.push(...newEdges);
  
  // 清理状态
  hideNodeList();
};

// 计算节点列表样式
const nodeListStyle = computed(() => ({
  position: 'fixed',
  left: `${nodeListPosition.value.x}px`,
  top: `${nodeListPosition.value.y}px`,
  transform: 'translate(-50%, 0)',
}));

// 添加画布点击处理函数
const handleCanvasClick = (event: MouseEvent) => {
  // 检查点击是否在菜单或加号按钮上
  const target = event.target as Element;
  if (!target.closest('.node-list') && !target.closest('.plus-button')) {
    hideNodeList();
  }
};

defineOptions({
  name: 'FlowCanvas'
});
</script>

<style scoped>
.flow-canvas {
  width: 100%;
  height: 100%;
  position: relative;
  background: #ffffff;
  overflow: hidden;
  cursor: grab;
}

/* 拖拽时显示抓取中的图标 */
.flow-canvas:active {
  cursor: grabbing;
}

.grid-background {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-image: radial-gradient(circle at center, #e5e5e5 1px, transparent 1px);
  pointer-events: none;
  will-change: background-position;
}

.transform-container {
  position: absolute;
  width: 100%;
  height: 100%;
  transition: transform 0.05s linear;
  pointer-events: auto;
  overflow: visible;
}

.zoom-controls {
  position: absolute;
  bottom: 20px;
  right: 20px;
  background: white;
  padding: 8px;
  border-radius: 4px;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
  display: flex;
  align-items: center;
  gap: 8px;
}

.zoom-controls button {
  width: 24px;
  height: 24px;
  border: 1px solid #ddd;
  background: white;
  border-radius: 4px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}

.zoom-controls button:hover {
  background: #f5f5f5;
}

.edges-layer {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 1;
  overflow: visible;
  pointer-events: none;
}

.nodes-container {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 2;
}

.edge-hitbox {
  stroke: transparent;
  stroke-width: 12px; /* 更宽的点击区域 */
  pointer-events: stroke;
  cursor: pointer;
}

.edge-path {
  pointer-events: none; /* 实际显示的线条不需要响应事件 */
  marker-end: url(#arrow);
  stroke: #b1b1b7;
  stroke-width: 1.5;
  fill: none;
}

.temp-edge {
  pointer-events: none;
  stroke: #666;
  stroke-dasharray: 5,5;
  stroke-width: 1.5;
}

/* 修改悬停效果的选择器 */
.edge-group:hover .edge-path {
  stroke: #666;
  stroke-width: 2;
}

/* 只让节点本身和端口响应事件 */
.flow-node {
  pointer-events: all;
  cursor: move;
}

.port {
  pointer-events: all;
  cursor: pointer;
}

.plus-button {
  cursor: pointer;
  pointer-events: all; /* 确保加号按钮可以接收事件 */
}

.plus-button circle {
  pointer-events: all;
}

.plus-button:hover circle {
  fill: #f5f5f5;
}

.node-list {
  position: fixed;
  background: white;
  border: 1px solid #ddd;
  border-radius: 4px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
  padding: 4px 0;
  z-index: 1000;
}

.node-list-item {
  padding: 4px 12px;
  cursor: pointer;
  white-space: nowrap;
}

.node-list-item:hover {
  background: #f5f5f5;
}
</style> 